package ragserverengine.neo4j

import io.ktor.server.application.Application
import ragserverengine.neo4j.core.Neo4jClient
import ragserverengine.neo4j.core.neo4jKey
import org.neo4j.driver.*
import kotlinx.serialization.json.*


class Neo4jService(private val application: Application) {

    private val neo4jClient: Neo4jClient by lazy {
        application.attributes[neo4jKey]
    }

    private val client: Driver get() = neo4jClient.getDriver()

    // 插入新的节点
    fun insertHandler(request: Neo4jInsertRequest): Neo4jInsertResponse {

        val session = client.session()

        return try {

            val cypher = buildCypher(request)
            print("insert cypher is: $cypher")
            session.executeWrite { tx -> tx.run(cypher).consume() }

            Neo4jInsertResponse(
                success = true,
                message = "Neo4j insert successfully"
            )
        } catch (e: Exception) {
            Neo4jInsertResponse(
                success = false,
                message = "Neo4j insert failed: ${e.message}"
            )
        } finally {
            session.close()
        }
    }

    private fun buildCypher(request: Neo4jInsertRequest): String {
        val props = request.attributes?.entries?.joinToString(", ") { (key, value) ->
            val formattedValue = when {
                value is JsonNull -> "null"
                value is JsonPrimitive && value.isString -> "'${value.content.replace("'", "\\'")}'"
                value is JsonPrimitive && value.booleanOrNull != null -> value.boolean.toString()
                value is JsonPrimitive && value.longOrNull != null -> value.long.toString()
                value is JsonPrimitive && value.doubleOrNull != null -> value.double.toString()
                value is JsonObject -> "{${value.entries.joinToString(", ") { (k, v) -> "$k:${formatJsonValue(v)}" }}}"
                value is JsonArray -> "[${value.joinToString(", ") { formatJsonValue(it) }}]"
                else -> "'${value.toString().replace("'", "\\'")}'"
            }
            "$key:$formattedValue"
        } ?: ""

        return if (props.isNotEmpty()) {
            "CREATE (n:${request.nodeName} {$props}) RETURN n"
        } else {
            "CREATE (n:${request.nodeName}) RETURN n"
        }
    }

    private fun formatJsonValue(value: JsonElement): String = when {
        value is JsonNull -> "null"
        value is JsonPrimitive && value.isString -> "'${value.content.replace("'", "\\'")}'"
        value is JsonPrimitive && value.booleanOrNull != null -> value.boolean.toString()
        value is JsonPrimitive && value.longOrNull != null -> value.long.toString()
        value is JsonPrimitive && value.doubleOrNull != null -> value.double.toString()
        value is JsonObject -> "{${value.entries.joinToString(", ") { (k, v) -> "$k:${formatJsonValue(v)}" }}}"
        value is JsonArray -> "[${value.joinToString(", ") { formatJsonValue(it) }}]"
        else -> "'${value.toString().replace("'", "\\'")}'"
    }


    fun queryHandler(request: Neo4jQueryRequest): Neo4jQueryResponse {
        val session = client.session()

        return try {
            // 构建查询语句
            // 如果有属性过滤，就生成 WHERE 条件
            val whereClause = request.attributes?.entries?.joinToString(" AND ") { (k, v) ->
                val valueStr = when {
                    v is JsonNull -> "null"
                    v is JsonPrimitive && v.isString -> "'${v.content.replace("'", "\\'")}'"
                    v is JsonPrimitive && v.booleanOrNull != null -> v.boolean.toString()
                    v is JsonPrimitive && v.longOrNull != null -> v.long.toString()
                    v is JsonPrimitive && v.doubleOrNull != null -> v.double.toString()
                    else -> "'${v.toString().replace("'", "\\'")}'"
                }
                "n.$k = $valueStr"
            }?.let { "WHERE $it" } ?: ""

            val cypher = "MATCH (n:${request.nodeName}) $whereClause RETURN n"
            print("Query cypher is: $cypher")

            // 执行查询
            val results = session.executeRead { tx ->
                tx.run(cypher).list()
            }

            val nodes: List<Map<String, JsonElement>> = results.map { record ->
                val node = record["n"].asNode()
                node.asMap().mapValues { (_, v) ->
                    when (v) {
                        null -> JsonNull
                        is Boolean -> JsonPrimitive(v)
                        is Number -> JsonPrimitive(v)
                        is String -> JsonPrimitive(v)
                        else -> JsonPrimitive(v.toString())
                    }
                }
            }

            Neo4jQueryResponse(
                success = true,
                data = nodes,
                message = "Query returned ${nodes.size} nodes"
            )

        } catch (e: Exception) {
            Neo4jQueryResponse(
                success = false,
                data = emptyList(),
                message = "Query failed: ${e.message}"
            )
        } finally {
            session.close()
        }
    }


    fun deleteHandler() {

    }


}